# coding: utf-8
import os
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait
import time, allure, pytest, random, string, pymysql
from Outputs.LOG import Log


class BasePage():
    LOG = Log()
    log = LOG.log2()

    # def __init__(self,driver):
    #     self.driver=driver

    def _locate_element(self, locator):
        """
        to locate element by selector
        :arg
        selector should be passed by an example with "i,xxx"
        "x,//*[@id='langs']/button"
        :returns
        DOM element
        """
        if locator is not None:
            element = self.driver.find_element(*locator)
        else:
            raise NameError("找不到指定的目标元素%s！" % locator)
        return element

    # 寻找元素
    def find_element(self, loc):
        return self._find_element(*loc)

    def _find_element(self, loc):
        with allure.step(f"显式等待元素{loc}加载,等待时间为10秒"):
            # 加一个显式等待，元素加载成功
            try:
                WebDriverWait(self.driver, 3, 1).until(EC.visibility_of_all_elements_located(loc),
                                                       message="%s页面中未能找到%s元素" + str(loc))
                element = self.driver.find_element(*loc)
                self.log.info("%s页面找到了%s元素" % (loc))
                return element
            except:
                self.log.error("%s页面未找到了%s元素" % (loc))
                raise Exception("%s页面未找到了%s元素" % (loc))

    # 填写文本框
    def send_keys(self, loc, keyword, click_f=True, clear_f=True):
        with allure.step(f"输入元素{loc}内容为：{keyword}"):
            try:
                # getattr相当于实现self.loc(将元组变成可调用的变量)
                # loc = getattr(self,"_%s"%loc)
                if click_f:
                    self._find_element(loc).click()
                if clear_f:
                    self._find_element(loc).clear()
                self._find_element(loc).send_keys(keyword)
            except AttributeError:
                # print("%s页面中未能找到%s元素" % (self, loc))
                raise Exception("找不到指定的目标元素%s！" % loc)  ###

    def click(self, loc):
        with allure.step(f"点击元素{loc}"):
            self._find_element(loc).click()

    def screenshot(self, name):
        """
        截图
        :param name: 截图的名称
        :return:
        """
        with allure.step(name):
            time.sleep(1)
            allure.attach(self.driver.get_screenshot_as_png(), name, allure.attachment_type.PNG)
            time.sleep(0.5)

    # 切换frame页
    def switch_to_frame(self, loc):
        iframe = self._find_element(loc)
        return self.driver.switch_to.frame(iframe)

    # 切换到默认窗口
    def switch_to_default(self):
        self.driver.switch_to.default_content()

    # 切换不同页面窗口
    def switch_to_window_by_title(self, title):
        for handle in self.driver.window_handles:
            self.driver.switch_to.window(handle)
            if self.driver.title == title:
                break
            self.driver.switch_to.default_content()

    # 执行js脚本
    def execute_js(self, src):
        with allure.step(f"执行js脚本"):
            self.driver.execute_script(src)

    # 控件截图为base64
    def save_element_snapshot_by_io(self, selector):
        el = self._locate_element(selector)
        return el.screenshot_as_base64

    # cookie 相关方法
    # 在driver初始化后清除cookie
    def clear_cookies(self):
        self.driver.delete_all_cookies()

    # 添加cookie，类型为dict
    def add_cookies(self, cookies):
        self.driver.add_cookie(cookie_dict=cookies)

    def add_cookie(self, cookie_dict):
        """
        Add single cookie by dict
        添加 单个 cookie
        如果该 cookie 已经存在，就先删除后，再添加
        :param cookie_dict: 字典类型，有两个key：name 和 value
        :return:
        """
        cookie_name = cookie_dict["name"]
        cookie_value = self.driver.get_cookie(cookie_name)
        if cookie_value is not None:
            self.driver.delete_cookie(cookie_name)
        self.driver.add_cookie(cookie_dict)

    def remove_cookie(self, name):
        """
        移除指定 name 的cookie
        :param name:
        :return:
        """
        # 检查 cookie 是否存在，存在就移除
        old_cookie_value = self.driver.get_cookie(name)
        if old_cookie_value is not None:
            self.driver.delete_cookie(name)

    # 浏览器本身相关方法
    def get_url(self, url):
        """
        刷新页面
        如果 url 是空值，就刷新当前页面，否则就刷新指定页面
        :param url: 默认值是空的
        :return:
        """
        with allure.step(f"刷新页面"):
            if url is None:
                self.log.error("未输入浏览器")
                self.driver.refresh()
            else:
                self.log.info(f"打开的网址为：=={url}==")
                self.driver.get(url)

    def maximize_window(self):
        """
        最大化当前浏览器的窗口
        :return:
        """
        with allure.step("最大化当前浏览器的窗口"):
            self.driver.maximize_window()

    def navigate(self, url):
        """
        打开 URL
        :param url:
        :return:
        """
        with allure.step("打开URL：" + url):
            self.driver.get(url)

    def quit(self):
        """
        退出驱动
        :return:
        """
        self.driver.quit()
        self.log.info("关闭浏览器")

    def close_browser(self):
        """
        关闭浏览器
        :return:
        """
        self.driver.close()

    def _locate_elements(self, locator):
        """
        to locate element by selector
        :arg
        selector should be passed by an example with "i,xxx"
        "x,//*[@id='langs']/button"
        :returns
        DOM element
        """
        if locator is not None:
            elements = self.driver.find_elements(*locator)
        else:
            raise NameError("Please enter a valid locator of targeting elements.")
        return elements

    def move_to(self, selector):
        """
        移动鼠标到指定元素
        :param selector:
        :return:
        """
        el = self._locate_element(selector)
        ActionChains(self.driver).move_to_element(el).perform()

    def right_click(self, selector):
        """
        鼠标右击
        :param selector:
        :return:
        """
        el = self._locate_element(selector)
        ActionChains(self.driver).context_click(el).perform()

    def double_click(self, selector):
        '''
        鼠标双击
        :param selector: （想要双击的元素）元素定位
        :return: 无
        '''
        ele = self._locate_element(selector)
        ActionChains(self.driver).double_click(ele).perform()

    def count_elements(self, selector):
        """
        数一下元素的个数
        :param selector: 定位符
        :return:
        """
        els = self._locate_elements(selector)
        return len(els)

    def drag_element(self, source, target):
        """
        拖拽元素
        :param source:
        :param target:
        :return:
        """
        el_source = self._locate_element(source)
        el_target = self._locate_element(target)

        if self.driver.w3c:
            ActionChains(self.driver).drag_and_drop(el_source, el_target).perform()
        else:
            ActionChains(self.driver).click_and_hold(el_source).perform()
            ActionChains(self.driver).move_to_element(el_target).perform()
            ActionChains(self.driver).release(el_target).perform()

    def lost_focus(self):
        """
        当前元素丢失焦点
        :return:
        """
        ActionChains(self.driver).key_down(Keys.TAB).key_up(Keys.TAB).perform()

    # 上传文件
    def upload_input(self, selector, file):
        '''
        上传文件 （ 标签为 input 类型，此类型最常见，最简单）
        :param selector: 上传按钮定位
        :param file: 将要上传的文件（绝对路径）
        :return: 无
        '''
        self._locate_element(selector).send_keys(file)

    # 通过iframe中存在的元素确定对应的iframe
    def iframe(self, loc):
        """
        识别iframe中包含的元素  来确定对应的iframe
        作用于无固定属性值的iframe
        :loc:iframe中存在的
        :return:
        """
        with allure.step(f"寻找存在{loc}iframe层，并将焦点选中对应的iframe"):
            try:
                i = 0
                while i < 10:
                    self.driver.switch_to.frame(int(i))
                    i = i + 1
                    # 判断元素是否存在   存在输出true  不存在输出false
                    try:
                        WebDriverWait(self.driver, 5, 1).until(EC.visibility_of_all_elements_located(loc))
                        b = True
                    except:
                        b = False
                    # 元素存在就退出循环  元素不存在就退出当前iframe
                    if b:
                        self.log.info(f"选择第{i}个iframe")
                        break
                    else:
                        self.driver.switch_to.default_content()  # 退出当前iframe
            except Exception as e:
                self.log.error('错误内容%s' % e)

    def rand(self, model):
        """
        随机数生成，可以生成五个随机字母或0~100000的数字
        :param model:
        :return:
        """
        with allure.step(f"进行随机数生成"):
            try:
                if model == 1:
                    allure.step("生成随机字母(五个字母组合)")
                    self.log.info("生成随机字母(五个字母组合)")
                    s = string.ascii_letters
                    a = random.choice(s) + random.choice(s) + random.choice(s) + random.choice(s) + random.choice(s)
                    return a
                else:
                    allure.step("生成0~100000的随机数字")
                    self.log.info("生成0~100000的随机数字")
                    r = random.randint(0, 100000)
                    return r
            except Exception as e:
                self.log.error(e)

    def con(self, sql):
        """
        查询数据库语句搜索所有的结果，默认查询 wkl_2022_dev_test 库
        :param sql:需要查询的语句
        :return: 返回查询的结果
        """
        with allure.step(f"查询sql语句搜索的所有结果，执行的sql语句为：{sql}"):
            try:
                db = pymysql.connect(host='rm-wz9396h79qmfn8jzbpo.mysql.rds.aliyuncs.com',  # 数据库ip地址
                                     port=3306,  # 端口
                                     user='wkl_test_22',  # 用户名
                                     password='W@wkl#2022%^',  # 数据库密码
                                     database='wkl_2022_dev_test')  # 查询的库
                # 使用cursor()方法获取操作游标
                cursor = db.cursor()
                # 执行SQL语句
                cursor.execute(sql)
                # 获取所有记录列表
                results = cursor.fetchall()
                return results
            except Exception as e:
                self.log.error(e)
            finally:
                db.close()  # 关闭链接

    def con_num(self, sql):
        """
        查询数据库语句的列数，默认查询 wkl_2022_dev_test 库
        :param sql:需要查询的语句
        :return: 返回查询的列数
        """
        with allure.step(f"查询sql搜索到的列数，执行的sql语句为：{sql}"):
            try:
                db = pymysql.connect(host='rm-wz9396h79qmfn8jzbpo.mysql.rds.aliyuncs.com',
                                     port=3306,
                                     user='wkl_test_22',
                                     password='W@wkl#2022%^',
                                     database='wkl_2022_dev_test')
                # 使用cursor()方法获取操作游标
                cursor = db.cursor()
                # 执行SQL语句
                sqlnum = cursor.execute(sql)
                # 获取所有记录列表
                # results = cursor.fetchall()
                return sqlnum
            except Exception as e:
                self.log.error(e)
            finally:
                db.close()  # 关闭链接

    # def upload_not_input(self, file, browser_type='Chrome'):
    #     '''
    #     上传文件 （ 标签不是 input 类型，使用 win32gui,得先安装 pywin32 依赖包）
    #                                             pip install pywin32
    #     :param browser_type: 浏览器类型（Chrome浏览器和Firefox浏览器的有区别）
    #     :param file: 将要上传的文件（绝对路径）
    #     单个文件：file1 = 'C:\\Users\\list_tuple_dict_test.py'
    #     同时上传多个文件：file2 = '"C:\\Users\\list_tuple_dict_test.py" "C:\\Users\\class_def.py"'
    #     :return: 无
    #     '''
    #     # Chrome 浏览器是'打开'
    #     # 对话框
    #     # 下载个 Spy++ 工具，定位“打开”窗口，定位到窗口的类(L):#32770, '打开'为窗口标题
    #     if browser_type == 'Chrome':
    #         dialog = win32gui.FindWindow('#32770', u'打开')
    #     elif browser_type == 'Firefox':
    #         # Firefox 浏览器是'文件上传'
    #         # 对话框
    #         dialog = win32gui.FindWindow('#32770', u'文件上传')
    #     ComboBoxEx32 = win32gui.FindWindowEx(dialog, 0, 'ComboBoxEx32', None)
    #     ComboBox = win32gui.FindWindowEx(ComboBoxEx32, 0, 'ComboBox', None)
    #     # 上面三句依次寻找对象，直到找到输入框Edit对象的句柄
    #     Edit = win32gui.FindWindowEx(ComboBox, 0, 'Edit', None)
    #     # 确定按钮Button
    #     button = win32gui.FindWindowEx(dialog, 0, 'Button', None)
    #     # 往输入框输入绝对地址
    #     win32gui.SendMessage(Edit, win32con.WM_SETTEXT, None, file)
    #     # 按button
    #     win32gui.SendMessage(dialog, win32con.WM_COMMAND, 1, button)
    #     # 获取属性
    #     # print(upload.get_attribute('value'))
